﻿using System;
using System.Collections.Generic;
using MugenInjection.Core.Components;
using MugenInjection.Interface.Components;
using MugenInjection.Logging.Infrastructure;
using MugenInjection.Logging.Interface;
using MugenInjection.Logging.Interface.Components;

namespace MugenInjection.Logging.Components
{
    /// <summary>
    /// A baseline definition of a logger factory, which tracks loggers as flyweights by type.
    /// </summary>
    public abstract class LoggerFactoryComponent : Component, ILoggerFactory
    {
        #region Fields

        private static readonly ILogMutator[] EmptyLogMutators = new ILogMutator[0];

        #endregion

        #region Overrides of Component

        /// <summary>
        /// Indicates whether the component is unique.
        /// </summary>
        public override sealed bool IsSingle
        {
            get { return true; }
        }

        /// <summary>
        /// Returns the component type. Need to find a component in the container.
        /// </summary>
        public override sealed Type ComponentType
        {
            get { return typeof (ILoggerFactory); }
        }

        /// <summary>
        /// Occurs on load component.
        /// </summary>
        protected override void OnLoad()
        {
            IsHaveMutators = Injector.Components.IsExist<ILogMutator>();
            Injector.Components.AddedComponent += ComponentsUpdate;
            Injector.Components.RemovedComponent += ComponentsUpdate;
        }

        /// <summary>
        /// Occurs on unload component.
        /// </summary>
        protected override void OnUnload()
        {
            IsHaveMutators = false;
            Injector.Components.AddedComponent -= ComponentsUpdate;
            Injector.Components.RemovedComponent -= ComponentsUpdate;
        }

        #endregion

        #region ILoggerFactory Members

        /// <summary>
        /// Gets the logger for the specified type, creating it if necessary.
        /// </summary>
        /// <param name="type">The type to create the logger for.</param>
        /// <returns>The newly-created logger.</returns>
        public ILogger GetLogger(Type type)
        {
            EnsureIsNotDisposed();
            return GetLoggerInternal(type);
        }

        #endregion

        #region Property

        protected internal bool IsHaveMutators { get; private set; }

        protected internal IEnumerable<IComponent> LogMutators
        {
            get { return IsHaveMutators ? Injector.Components.GetAll<ILogMutator>() : EmptyLogMutators; }
        }

        #endregion

        #region Method

        private void ComponentsUpdate(IComponent component)
        {
            if (component.ComponentType != typeof (ILogMutator)) return;
            IsHaveMutators = Injector.Components.IsExist<ILogMutator>();
        }

        #endregion

        #region Abstract or virtual method

        /// <summary>
        /// Gets the logger for the specified type, creating it if necessary.
        /// </summary>
        /// <param name="type">The type to create the logger for.</param>
        /// <returns>The newly-created logger.</returns>
        protected abstract LoggerBase GetLoggerInternal(Type type);

        #endregion
    }
}